package com.fattyCorps.game.mgr.event;

import com.fattyCorps.game.an.AEventListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

@Component
public class EventMgr implements CommandLineRunner {
    private class EventInvoker {
        public Object bean;
        public Method method;
    }

    @Autowired
    ApplicationContext appContext;

    public HashMap<EEvent, List<EventInvoker>> eventInvokerMap = new HashMap<>();

    @Override
    public void run(String... args) throws Exception {
        // 将需要监听事件的接口上增加监听注解，获取所有注入springboot的对象，将其中有监听注解的找出来，保存事件id->对象+调用函数集合的一个map，之后在有事件的时候，找到对象集合然后向其发事件
        String[] beanDefinitionNames = appContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            Object bean = appContext.getBean(beanDefinitionName);
            Method[] declaredMethods = bean.getClass().getDeclaredMethods();

            for (Method declaredMethod : declaredMethods) {
                AEventListener anEvent = (AEventListener) declaredMethod.getDeclaredAnnotation(AEventListener.class);
                if (anEvent != null) {
                    EventInvoker invoker = new EventInvoker();
                    invoker.bean = bean;
                    invoker.method = declaredMethod;

                    List<EventInvoker> invokers = eventInvokerMap.get(anEvent.value());
                    if (invokers == null) {
                        invokers = new ArrayList<>();
                        eventInvokerMap.put(anEvent.value(), invokers);
                    }

                    invokers.add(invoker);
                }
            }
        }
    }

    public void sendEvent(EEvent event, Object... args) {
        List<EventInvoker> invokers = eventInvokerMap.get(event);
        if (invokers != null) {
            for (EventInvoker invoker : invokers) {
                try {
                    invoker.method.setAccessible(true);
                    invoker.method.invoke(invoker.bean, args);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
